﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <time.h>
#include <stdint.h>
#include <stddef.h> // 用于offsetof
#include <errno.h>  // 用于错误处理

// ======================
// 常量定义
// ======================
#define MAX_PATH_LEN 260
#define RLE_FLAG 0xFF
#define RZP_MAGIC "RZP"
#define RZP_VERSION 3  // 版本号升级

// ======================
// 结构体定义
// ======================

// 文件条目结构
typedef struct FileEntry {
    char relative_path[MAX_PATH_LEN];
    char absolute_path[MAX_PATH_LEN];
    uint64_t file_size;
    struct FileEntry* next;
} FileEntry;

// RZP文件头结构
#pragma pack(push, 1)
typedef struct {
    char magic[3];      // 魔数 "RZP"
    uint8_t version;    // 版本号
} RzpHeader;

// 文件条目头（存储在压缩文件中）
typedef struct {
    uint16_t path_len;  // 路径长度
    uint64_t orig_size; // 原始大小
    uint64_t comp_size; // 压缩后大小
} FileEntryHeader;
#pragma pack(pop)

// ======================
// 函数声明
// ======================

// 文件遍历
void find_files(const char* base_path, FileEntry** file_list);
void find_files_recursive(const char* base_path, const char* rel_path, FileEntry** file_list);
void add_file_entry(FileEntry** list, const char* rel_path, const char* abs_path, uint64_t size);
void free_file_list(FileEntry* list);
void print_file_list(const FileEntry* list);
int file_count(FileEntry* list);

// RLE算法
void rle_compress(const uint8_t* input, size_t input_size, uint8_t** output, size_t* output_size);
void rle_decompress(const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size);
void run_rle_tests();

// 压缩功能
void compress_file(const char* input_path, const char* output_path);
void compress_directory(const char* input_dir, const char* output_path);
void compress_files(FileEntry* file_list, const char* output_path);
void compress_multiple_files(int file_count, char* file_paths[], const char* output_path);
void compress_current_directory(const char* output_path);

// 解压功能
void decompress_file(const char* input_path);
void create_path_directories(const char* path);
void sanitize_path(const char* input_path, size_t path_len, char* output_path);
void normalize_path(char* path);

// 辅助功能
void print_statistics(clock_t start_time, uint64_t total_orig, uint64_t total_comp,
    int success_count, int fail_count);
void print_decompress_statistics(clock_t start_time, int success_count, int fail_count,
    uint64_t total_orig, uint64_t total_comp, const char* output_dir);
void print_usage(const char* program_name);
int validate_file_size(uint64_t size, const char* file_path);
int verify_file_read(const char* path, uint64_t expected_size);

// ======================
// 路径处理函数实现
// ======================

void normalize_path(char* path) {
    for (char* p = path; *p; p++) {
        if (*p == '/') *p = '\\';
    }
}

void sanitize_path(const char* input_path, size_t path_len, char* output_path) {
    size_t out_idx = 0;
    int consecutive_dots = 0;

    for (size_t i = 0; i < path_len; i++) {
        if (input_path[i] == '\\' || input_path[i] == '/') {
            if (out_idx > 0 && output_path[out_idx - 1] != '\\') {
                output_path[out_idx++] = '\\';
            }
            consecutive_dots = 0;
            continue;
        }

        if (input_path[i] == '.') {
            consecutive_dots++;
            if (consecutive_dots >= 2 && i >= 2 &&
                (input_path[i - 1] == '.' && (input_path[i - 2] == '\\' || input_path[i - 2] == '/'))) {
                if (out_idx > 0) output_path[out_idx - 1] = '_';
                output_path[out_idx++] = '_';
            }
            else {
                output_path[out_idx++] = '.';
            }
            continue;
        }

        consecutive_dots = 0;

        if (input_path[i] == ':' || input_path[i] == '*' ||
            input_path[i] == '?' || input_path[i] == '"' ||
            input_path[i] == '<' || input_path[i] == '>' ||
            input_path[i] == '|' || input_path[i] < 32) {
            output_path[out_idx++] = '_';
        }
        else {
            output_path[out_idx++] = input_path[i];
        }
    }

    if (out_idx > 0 && output_path[out_idx - 1] == '\\') {
        out_idx--;
    }

    output_path[out_idx] = '\0';

    if (out_idx == 0) {
        strcpy(output_path, "unnamed_file");
    }
}

int validate_file_size(uint64_t size, const char* file_path) {
    const uint64_t MAX_REASONABLE_SIZE = 10ULL * 1024 * 1024 * 1024 * 1024; // 10TB

    if (size > MAX_REASONABLE_SIZE) {
        fprintf(stderr, "警告: 可疑的文件大小 %llu 字节 (%s)\n",
            (unsigned long long)size, file_path);
        return 0;
    }

    return 1;
}

// ======================
// 文件遍历函数实现
// ======================

void add_file_entry(FileEntry** list, const char* rel_path, const char* abs_path, uint64_t size) {
    if (!validate_file_size(size, abs_path)) {
        fprintf(stderr, "跳过文件: %s (大小可疑)\n", abs_path);
        return;
    }

    FileEntry* new_entry = (FileEntry*)malloc(sizeof(FileEntry));
    if (!new_entry) {
        fprintf(stderr, "内存分配失败: 无法创建文件条目\n");
        return;
    }

    strncpy(new_entry->relative_path, rel_path, MAX_PATH_LEN - 1);
    new_entry->relative_path[MAX_PATH_LEN - 1] = '\0';

    strncpy(new_entry->absolute_path, abs_path, MAX_PATH_LEN - 1);
    new_entry->absolute_path[MAX_PATH_LEN - 1] = '\0';

    new_entry->file_size = size;
    new_entry->next = NULL;

    if (*list == NULL) {
        *list = new_entry;
    }
    else {
        FileEntry* current = *list;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_entry;
    }
}

void find_files_recursive(const char* base_path, const char* current_rel, FileEntry** file_list) {
    char search_path[MAX_PATH_LEN];
    char full_path[MAX_PATH_LEN];
    char new_rel_path[MAX_PATH_LEN];

    if (strlen(current_rel) > 0) {
        snprintf(search_path, MAX_PATH_LEN, "%s\\%s\\*", base_path, current_rel);
    }
    else {
        snprintf(search_path, MAX_PATH_LEN, "%s\\*", base_path);
    }

    normalize_path(search_path);

    WIN32_FIND_DATAA find_data;
    HANDLE hFind = FindFirstFileA(search_path, &find_data);

    if (hFind == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        if (error != ERROR_FILE_NOT_FOUND) {
            fprintf(stderr, "警告: 无法访问目录 %s (错误代码: %lu)\n", search_path, error);
        }
        return;
    }

    do {
        if (strcmp(find_data.cFileName, ".") == 0 ||
            strcmp(find_data.cFileName, "..") == 0) {
            continue;
        }

        if (strlen(current_rel) > 0) {
            snprintf(full_path, MAX_PATH_LEN, "%s\\%s\\%s", base_path, current_rel, find_data.cFileName);
            snprintf(new_rel_path, MAX_PATH_LEN, "%s\\%s", current_rel, find_data.cFileName);
        }
        else {
            snprintf(full_path, MAX_PATH_LEN, "%s\\%s", base_path, find_data.cFileName);
            snprintf(new_rel_path, MAX_PATH_LEN, "%s", find_data.cFileName);
        }

        normalize_path(full_path);
        normalize_path(new_rel_path);

        if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            find_files_recursive(base_path, new_rel_path, file_list);
        }
        else {
            WIN32_FILE_ATTRIBUTE_DATA fileAttr;
            if (GetFileAttributesExA(full_path, GetFileExInfoStandard, &fileAttr)) {
                ULARGE_INTEGER size;
                size.HighPart = fileAttr.nFileSizeHigh;
                size.LowPart = fileAttr.nFileSizeLow;
                add_file_entry(file_list, new_rel_path, full_path, size.QuadPart);
            }
            else {
                fprintf(stderr, "警告: 无法获取文件大小 %s\n", full_path);
            }
        }
    } while (FindNextFileA(hFind, &find_data));

    FindClose(hFind);
}

void find_files(const char* base_path, FileEntry** file_list) {
    DWORD attr = GetFileAttributesA(base_path);
    if (attr == INVALID_FILE_ATTRIBUTES) {
        fprintf(stderr, "错误: 路径不存在 %s\n", base_path);
        return;
    }

    char normalized_base[MAX_PATH_LEN];
    strncpy(normalized_base, base_path, MAX_PATH_LEN);
    normalize_path(normalized_base);

    if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
        HANDLE hFile = CreateFileA(normalized_base, GENERIC_READ, FILE_SHARE_READ,
            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "错误: 无法打开文件 %s\n", normalized_base);
            return;
        }

        LARGE_INTEGER file_size;
        if (!GetFileSizeEx(hFile, &file_size)) {
            fprintf(stderr, "警告: 无法获取文件大小 %s\n", normalized_base);
            file_size.QuadPart = 0;
        }

        CloseHandle(hFile);

        const char* filename = strrchr(normalized_base, '\\');
        if (!filename) filename = normalized_base;
        else filename++;

        add_file_entry(file_list, filename, normalized_base, file_size.QuadPart);
        return;
    }

    find_files_recursive(normalized_base, "", file_list);
}

void free_file_list(FileEntry* list) {
    while (list != NULL) {
        FileEntry* next = list->next;
        free(list);
        list = next;
    }
}

void print_file_list(const FileEntry* list) {
    printf("文件列表:\n");
    printf("%-40s %-20s %s\n", "相对路径", "大小", "绝对路径");
    printf("------------------------------------------------------------\n");

    int count = 0;
    uint64_t total_size = 0;

    while (list != NULL) {
        printf("%-40s %-20llu %s\n",
            list->relative_path,
            list->file_size,
            list->absolute_path);

        total_size += list->file_size;
        count++;
        list = list->next;
    }

    printf("------------------------------------------------------------\n");
    printf("总计: %d 个文件, %llu 字节 (%.2f MB)\n",
        count, total_size, (double)total_size / (1024 * 1024));
}

// ======================
// RLE压缩算法实现（确保正确性）
// ======================

void rle_compress(const uint8_t* input, size_t input_size, uint8_t** output, size_t* output_size) {
    // 处理空输入
    if (input_size == 0) {
        *output = NULL;
        *output_size = 0;
        return;
    }

    // 分配输出缓冲区（最坏情况：无压缩）
    *output = (uint8_t*)malloc(input_size * 2);
    if (*output == NULL) {
        fprintf(stderr, "错误: 内存分配失败\n");
        *output_size = 0;
        return;
    }

    size_t in_idx = 0;
    size_t out_idx = 0;

    while (in_idx < input_size) {
        uint8_t current_byte = input[in_idx];
        size_t run_length = 1;

        // 计算连续重复字节数
        while (in_idx + run_length < input_size &&
            input[in_idx + run_length] == current_byte &&
            run_length < 255) {
            run_length++;
        }

        if (run_length >= 3) {
            // 确保有足够空间
            if (out_idx + 3 > input_size * 2) break;

            (*output)[out_idx++] = RLE_FLAG;
            (*output)[out_idx++] = (uint8_t)run_length;
            (*output)[out_idx++] = current_byte;
            in_idx += run_length;
        }
        else {
            // 查找非重复序列结束点
            size_t non_run_length = 1;
            while (in_idx + non_run_length < input_size) {
                // 检查是否开始重复序列
                if (in_idx + non_run_length + 2 < input_size &&
                    input[in_idx + non_run_length] == input[in_idx + non_run_length + 1] &&
                    input[in_idx + non_run_length] == input[in_idx + non_run_length + 2]) {
                    break;
                }
                non_run_length++;
                if (non_run_length == 255) break;
            }

            // 确保有足够空间
            if (out_idx + 1 + non_run_length > input_size * 2) break;

            (*output)[out_idx++] = (uint8_t)non_run_length;
            memcpy(*output + out_idx, input + in_idx, non_run_length);
            out_idx += non_run_length;
            in_idx += non_run_length;
        }
    }

    // 调整到实际大小
    *output = (uint8_t*)realloc(*output, out_idx);
    *output_size = out_idx;
}

void rle_decompress(const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size) {
    size_t in_idx = 0;
    size_t out_idx = 0;

    while (in_idx < input_size && out_idx < output_size) {
        if (input[in_idx] == RLE_FLAG && in_idx + 2 < input_size) {
            uint8_t count = input[in_idx + 1];
            uint8_t value = input[in_idx + 2];
            memset(output + out_idx, value, count);
            out_idx += count;
            in_idx += 3;
        }
        else {
            uint8_t count = input[in_idx++];
            if (in_idx + count > input_size) break;
            if (out_idx + count > output_size) break;
            memcpy(output + out_idx, input + in_idx, count);
            out_idx += count;
            in_idx += count;
        }
    }
}

// ======================
// 压缩核心函数（彻底重写）
// ======================

void compress_files(FileEntry* file_list, const char* output_path) {
    if (file_list == NULL) {
        fprintf(stderr, "错误: 文件列表为空\n");
        return;
    }

    FILE* out_file = fopen(output_path, "wb");
    if (out_file == NULL) {
        fprintf(stderr, "错误: 无法创建输出文件 %s (原因: %s)\n",
            output_path, strerror(errno));
        return;
    }

    clock_t start_time = clock();

    // 计算文件总数
    uint32_t file_count = 0;
    FileEntry* current = file_list;
    while (current != NULL) {
        file_count++;
        current = current->next;
    }

    // 写入文件头
    RzpHeader header;
    memcpy(header.magic, RZP_MAGIC, 3);
    header.version = RZP_VERSION;
    if (fwrite(&header, sizeof(RzpHeader), 1, out_file) != 1) {
        fprintf(stderr, "错误: 文件头写入失败\n");
        fclose(out_file);
        return;
    }

    // 写入文件数量
    if (fwrite(&file_count, sizeof(uint32_t), 1, out_file) != 1) {
        fprintf(stderr, "错误: 文件数量写入失败\n");
        fclose(out_file);
        return;
    }

    // 初始化统计信息
    uint64_t total_orig_size = 0;
    uint64_t total_comp_size = 0;
    int success_count = 0;
    int fail_count = 0;

    // 第一遍：写入文件条目信息
    current = file_list;
    while (current != NULL) {
        // 准备文件条目头
        FileEntryHeader entry_header;
        entry_header.path_len = (uint16_t)strlen(current->relative_path);
        entry_header.orig_size = current->file_size;
        entry_header.comp_size = 0; // 稍后填充

        // 写入文件条目头
        if (fwrite(&entry_header, sizeof(FileEntryHeader), 1, out_file) != 1) {
            fprintf(stderr, "错误: 文件条目头写入失败 %s\n", current->relative_path);
            fail_count++;
            current = current->next;
            continue;
        }

        // 写入相对路径
        if (fwrite(current->relative_path, 1, entry_header.path_len, out_file) != entry_header.path_len) {
            fprintf(stderr, "错误: 路径写入失败 %s\n", current->relative_path);
            fail_count++;
            current = current->next;
            continue;
        }

        current = current->next;
    }

    // 第二遍：写入压缩数据
    current = file_list;
    while (current != NULL) {
        // 记录当前位置（用于更新压缩大小）
        long entry_position = ftell(out_file);

        // 读取文件内容
        FILE* in_file = fopen(current->absolute_path, "rb");
        if (!in_file) {
            fprintf(stderr, "错误: 无法打开文件 %s (原因: %s)\n",
                current->absolute_path, strerror(errno));
            fail_count++;
            current = current->next;
            continue;
        }

        // 分配内存读取文件内容
        uint8_t* file_data = (uint8_t*)malloc(current->file_size);
        if (!file_data) {
            fprintf(stderr, "错误: 内存不足, 跳过文件 %s\n", current->relative_path);
            fclose(in_file);
            fail_count++;
            current = current->next;
            continue;
        }

        // 读取文件数据
        size_t read_size = fread(file_data, 1, current->file_size, in_file);
        fclose(in_file);

        if (read_size != current->file_size) {
            fprintf(stderr, "错误: 文件读取不完整 %s (%zu/%llu)\n",
                current->relative_path, read_size, current->file_size);
            free(file_data);
            fail_count++;
            current = current->next;
            continue;
        }

        // 压缩数据
        uint8_t* compressed_data = NULL;
        size_t comp_size = 0;
        rle_compress(file_data, current->file_size, &compressed_data, &comp_size);

        if (comp_size == 0 || compressed_data == NULL) {
            fprintf(stderr, "错误: 压缩失败 %s (压缩后大小为零)\n", current->relative_path);
            free(file_data);
            fail_count++;
            current = current->next;
            continue;
        }

        // 写入压缩数据
        size_t written = fwrite(compressed_data, 1, comp_size, out_file);
        if (written != comp_size) {
            fprintf(stderr, "错误: 压缩数据写入不完整 %s (%zu/%zu)\n",
                current->relative_path, written, comp_size);
            free(file_data);
            free(compressed_data);
            fail_count++;
            current = current->next;
            continue;
        }

        // 更新统计信息
        total_orig_size += current->file_size;
        total_comp_size += comp_size;
        success_count++;

        // 打印进度
        printf("压缩: %s [原始: %llu 压缩: %zu 比率: %.1f%%]\n",
            current->relative_path,
            current->file_size,
            comp_size,
            (1.0 - (double)comp_size / current->file_size) * 100.0);

        // 释放资源
        free(file_data);
        free(compressed_data);

        current = current->next;
    }

    // 关闭输出文件
    if (fclose(out_file) != 0) {
        fprintf(stderr, "警告: 关闭输出文件失败\n");
    }

    // 打印统计信息
    print_statistics(start_time, total_orig_size, total_comp_size, success_count, fail_count);

    // 验证输出文件大小
    FILE* check_file = fopen(output_path, "rb");
    if (check_file) {
        fseek(check_file, 0, SEEK_END);
        long file_size = ftell(check_file);
        fclose(check_file);

        if (file_size == 0) {
            fprintf(stderr, "严重错误: 输出文件大小为0字节\n");
        }
        else {
            printf("输出文件大小: %ld 字节\n", file_size);
        }
    }
    else {
        fprintf(stderr, "警告: 无法验证输出文件大小\n");
    }
}

// ======================
// 其他压缩函数
// ======================

void compress_file(const char* input_path, const char* output_path) {
    FileEntry* list = (FileEntry*)malloc(sizeof(FileEntry));
    if (!list) {
        fprintf(stderr, "错误: 内存分配失败\n");
        return;
    }

    HANDLE hFile = CreateFileA(input_path, GENERIC_READ, FILE_SHARE_READ,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "错误: 无法打开文件 %s\n", input_path);
        free(list);
        return;
    }

    LARGE_INTEGER file_size;
    if (!GetFileSizeEx(hFile, &file_size)) {
        fprintf(stderr, "警告: 无法获取文件大小 %s\n", input_path);
        file_size.QuadPart = 0;
    }

    CloseHandle(hFile);

    const char* filename = strrchr(input_path, '\\');
    if (!filename) filename = input_path;
    else filename++;

    strncpy(list->relative_path, filename, MAX_PATH_LEN);
    strncpy(list->absolute_path, input_path, MAX_PATH_LEN);
    list->file_size = file_size.QuadPart;
    list->next = NULL;

    compress_files(list, output_path);
    free(list);
}

void compress_directory(const char* input_dir, const char* output_path) {
    FileEntry* file_list = NULL;
    find_files(input_dir, &file_list);

    if (file_list == NULL) {
        fprintf(stderr, "警告: 目录 %s 中没有找到文件\n", input_dir);
        return;
    }

    compress_files(file_list, output_path);
    free_file_list(file_list);
}

void compress_multiple_files(int file_count, char* file_paths[], const char* output_path) {
    printf("压缩 %d 个文件到 %s\n", file_count, output_path);

    FileEntry* file_list = NULL;
    int valid_files = 0;

    for (int i = 0; i < file_count; i++) {
        char* input_path = file_paths[i];

        DWORD attr = GetFileAttributesA(input_path);
        if (attr == INVALID_FILE_ATTRIBUTES) {
            fprintf(stderr, "警告: 文件不存在 %s, 跳过\n", input_path);
            continue;
        }

        if (attr & FILE_ATTRIBUTE_DIRECTORY) {
            fprintf(stderr, "警告: %s 是目录, 跳过\n", input_path);
            continue;
        }

        HANDLE hFile = CreateFileA(input_path, GENERIC_READ, FILE_SHARE_READ,
            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "警告: 无法打开文件 %s, 跳过\n", input_path);
            continue;
        }

        LARGE_INTEGER file_size;
        if (!GetFileSizeEx(hFile, &file_size)) {
            fprintf(stderr, "警告: 无法获取文件大小 %s, 跳过\n", input_path);
            CloseHandle(hFile);
            continue;
        }

        CloseHandle(hFile);

        const char* filename = strrchr(input_path, '\\');
        if (!filename) filename = strrchr(input_path, '/');
        if (!filename) filename = input_path;
        else filename++;

        add_file_entry(&file_list, filename, input_path, file_size.QuadPart);
        valid_files++;
    }

    if (valid_files == 0) {
        fprintf(stderr, "错误: 没有有效文件可压缩\n");
        return;
    }

    printf("找到 %d 个有效文件:\n", valid_files);
    print_file_list(file_list);

    compress_files(file_list, output_path);
    free_file_list(file_list);
}

void compress_current_directory(const char* output_path) {
    printf("压缩当前目录所有文件到 %s\n", output_path);

    char current_dir[MAX_PATH_LEN];
    if (!GetCurrentDirectoryA(MAX_PATH_LEN, current_dir)) {
        fprintf(stderr, "错误: 无法获取当前目录\n");
        return;
    }

    WIN32_FIND_DATAA find_data;
    HANDLE hFind;
    char search_path[MAX_PATH_LEN];
    snprintf(search_path, MAX_PATH_LEN, "%s\\*", current_dir);

    FileEntry* file_list = NULL;
    int file_count = 0;

    hFind = FindFirstFileA(search_path, &find_data);
    if (hFind == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "错误: 无法枚举目录 %s\n", current_dir);
        return;
    }

    do {
        if (strcmp(find_data.cFileName, ".") == 0 ||
            strcmp(find_data.cFileName, "..") == 0) {
            continue;
        }

        if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            continue;
        }

        char full_path[MAX_PATH_LEN];
        snprintf(full_path, MAX_PATH_LEN, "%s\\%s", current_dir, find_data.cFileName);

        ULARGE_INTEGER file_size;
        file_size.HighPart = find_data.nFileSizeHigh;
        file_size.LowPart = find_data.nFileSizeLow;

        add_file_entry(&file_list, find_data.cFileName, full_path, file_size.QuadPart);
        file_count++;

    } while (FindNextFileA(hFind, &find_data));

    FindClose(hFind);

    if (file_count == 0) {
        fprintf(stderr, "警告: 当前目录没有文件\n");
        return;
    }

    printf("找到 %d 个文件:\n", file_count);
    print_file_list(file_list);

    compress_files(file_list, output_path);
    free_file_list(file_list);
}

// ======================
// 解压功能实现
// ======================

void create_path_directories(const char* file_path) {
    char dir_path[MAX_PATH_LEN];
    strncpy(dir_path, file_path, MAX_PATH_LEN);

    char* last_sep = strrchr(dir_path, '\\');
    if (!last_sep) last_sep = strrchr(dir_path, '/');

    if (last_sep) {
        *last_sep = '\0';

        char* current = dir_path;
        while (*current) {
            if (*current == '\\' || *current == '/') {
                char temp = *current;
                *current = '\0';

                if (*dir_path != '\0') {
                    DWORD attr = GetFileAttributesA(dir_path);
                    if (attr == INVALID_FILE_ATTRIBUTES) {
                        if (!CreateDirectoryA(dir_path, NULL)) {
                            DWORD err = GetLastError();
                            if (err != ERROR_ALREADY_EXISTS) {
                                fprintf(stderr, "警告: 无法创建目录 %s (错误: %lu)\n", dir_path, err);
                            }
                        }
                    }
                }

                *current = temp;
            }
            current++;
        }

        if (*dir_path != '\0') {
            CreateDirectoryA(dir_path, NULL);
        }
    }
}

void decompress_file(const char* input_path) {
    clock_t start_time = clock();

    FILE* in_file = fopen(input_path, "rb");
    if (!in_file) {
        fprintf(stderr, "错误: 无法打开输入文件 %s\n", input_path);
        return;
    }

    RzpHeader header;
    if (fread(&header, sizeof(RzpHeader), 1, in_file) != 1) {
        fprintf(stderr, "错误: 无法读取文件头\n");
        fclose(in_file);
        return;
    }

    if (memcmp(header.magic, RZP_MAGIC, 3) != 0) {
        fprintf(stderr, "错误: 无效文件格式\n");
        fclose(in_file);
        return;
    }

    if (header.version != RZP_VERSION) {
        fprintf(stderr, "错误: 不支持的版本号 (%d), 需要版本 %d\n", header.version, RZP_VERSION);
        fclose(in_file);
        return;
    }

    uint32_t file_count;
    if (fread(&file_count, sizeof(uint32_t), 1, in_file) != 1) {
        fprintf(stderr, "错误: 无法读取文件数量\n");
        fclose(in_file);
        return;
    }

    printf("解压缩 %u 个文件...\n", file_count);

    char output_dir[MAX_PATH_LEN];
    time_t now = time(NULL);
    snprintf(output_dir, MAX_PATH_LEN, "unzipped_%lld", (long long)now);

    if (GetFileAttributesA(output_dir) == INVALID_FILE_ATTRIBUTES) {
        if (!CreateDirectoryA(output_dir, NULL)) {
            fprintf(stderr, "错误: 无法创建输出目录 %s\n", output_dir);
            fclose(in_file);
            return;
        }
    }

    uint64_t total_orig_size = 0;
    uint64_t total_comp_size = 0;
    int success_count = 0;
    int fail_count = 0;

    for (uint32_t i = 0; i < file_count; i++) {
        FileEntryHeader entry_header;
        if (fread(&entry_header, sizeof(FileEntryHeader), 1, in_file) != 1) {
            fprintf(stderr, "错误: 无法读取文件条目头 %d\n", i);
            fail_count++;
            continue;
        }

        char* raw_path = (char*)malloc(entry_header.path_len + 1);
        if (!raw_path) {
            fprintf(stderr, "错误: 内存分配失败 (路径)\n");
            fail_count++;
            continue;
        }

        if (fread(raw_path, 1, entry_header.path_len, in_file) != entry_header.path_len) {
            fprintf(stderr, "错误: 无法读取路径 %d\n", i);
            free(raw_path);
            fail_count++;
            continue;
        }
        raw_path[entry_header.path_len] = '\0';

        char safe_path[MAX_PATH_LEN];
        sanitize_path(raw_path, entry_header.path_len, safe_path);

        char full_path[MAX_PATH_LEN];
        snprintf(full_path, MAX_PATH_LEN, "%s\\%s", output_dir, safe_path);

        create_path_directories(full_path);

        uint8_t* compressed_data = (uint8_t*)malloc(entry_header.comp_size);
        if (!compressed_data) {
            fprintf(stderr, "错误: 内存分配失败 (压缩数据) %s\n", safe_path);
            free(raw_path);
            fail_count++;
            continue;
        }

        if (fread(compressed_data, 1, entry_header.comp_size, in_file) != entry_header.comp_size) {
            fprintf(stderr, "错误: 无法读取压缩数据 %s\n", safe_path);
            free(raw_path);
            free(compressed_data);
            fail_count++;
            continue;
        }

        uint8_t* decompressed_data = (uint8_t*)malloc(entry_header.orig_size);
        if (!decompressed_data) {
            fprintf(stderr, "错误: 内存分配失败 (解压数据) %s\n", safe_path);
            free(raw_path);
            free(compressed_data);
            fail_count++;
            continue;
        }

        rle_decompress(compressed_data, entry_header.comp_size, decompressed_data, entry_header.orig_size);

        FILE* out_file = fopen(full_path, "wb");
        if (!out_file) {
            fprintf(stderr, "错误: 无法创建文件 %s\n", full_path);
            free(raw_path);
            free(compressed_data);
            free(decompressed_data);
            fail_count++;
            continue;
        }

        size_t written = fwrite(decompressed_data, 1, entry_header.orig_size, out_file);
        fclose(out_file);

        if (written != entry_header.orig_size) {
            fprintf(stderr, "警告: 文件写入不完整 %s (%zu/%llu)\n",
                full_path, written, entry_header.orig_size);
            fail_count++;
        }
        else {
            printf("解压: %s [原始: %llu 压缩: %llu]\n",
                safe_path, entry_header.orig_size, entry_header.comp_size);
            success_count++;
        }

        total_orig_size += entry_header.orig_size;
        total_comp_size += entry_header.comp_size;

        free(raw_path);
        free(compressed_data);
        free(decompressed_data);
    }

    fclose(in_file);

    print_decompress_statistics(start_time, success_count, fail_count,
        total_orig_size, total_comp_size, output_dir);
}

// ======================
// 辅助函数实现
// ======================

void print_statistics(clock_t start_time, uint64_t total_orig, uint64_t total_comp,
    int success_count, int fail_count) {
    double elapsed = (double)(clock() - start_time) / CLOCKS_PER_SEC;
    double ratio = 0.0;

    if (total_orig > 0) {
        ratio = (1.0 - (double)total_comp / total_orig) * 100.0;
    }

    printf("\n======= 压缩统计 =======\n");
    printf("成功文件: %d\n", success_count);
    printf("失败文件: %d\n", fail_count);
    printf("原始总大小: %llu 字节 (%.2f MB)\n", total_orig, (double)total_orig / (1024 * 1024));
    printf("压缩总大小: %llu 字节 (%.2f MB)\n", total_comp, (double)total_comp / (1024 * 1024));
    printf("压缩比率: %.2f%%\n", ratio);
    printf("耗时: %.3f 秒\n", elapsed);
    printf("=======================\n");

    if (fail_count > 0) {
        printf("警告: %d 个文件压缩失败\n", fail_count);
    }
}

void print_decompress_statistics(clock_t start_time, int success_count, int fail_count,
    uint64_t total_orig, uint64_t total_comp, const char* output_dir) {
    double elapsed = (double)(clock() - start_time) / CLOCKS_PER_SEC;
    double ratio = 0.0;

    if (total_orig > 0) {
        ratio = (double)total_comp / total_orig * 100.0;
    }

    printf("\n======= 解压统计 =======\n");
    printf("输出目录: %s\n", output_dir);
    printf("成功文件: %d\n", success_count);
    printf("失败文件: %d\n", fail_count);
    printf("原始总大小: %llu 字节 (%.2f MB)\n", total_orig, (double)total_orig / (1024 * 1024));
    printf("压缩总大小: %llu 字节 (%.2f MB)\n", total_comp, (double)total_comp / (1024 * 1024));
    printf("压缩比率: %.2f%%\n", ratio);
    printf("耗时: %.3f 秒\n", elapsed);
    printf("=======================\n");

    if (fail_count > 0) {
        printf("警告: %d 个文件解压失败\n", fail_count);
    }
}

int verify_file_read(const char* path, uint64_t expected_size) {
    FILE* file = fopen(path, "rb");
    if (!file) {
        fprintf(stderr, "验证错误: 无法打开文件 %s\n", path);
        return 0;
    }

    fseek(file, 0, SEEK_END);
    long actual_size = ftell(file);
    fclose(file);

    if ((uint64_t)actual_size != expected_size) {
        fprintf(stderr, "验证错误: 文件大小不匹配 %s (预期: %llu, 实际: %ld)\n",
            path, expected_size, actual_size);
        return 0;
    }

    return 1;
}

// ======================
// 主函数
// ======================

int main(int argc, char* argv[]) {
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }

    // 处理压缩命令
    if (strcmp(argv[1], "zip") == 0) {
        if (argc < 4) {
            printf("错误: 压缩命令需要至少一个输入文件和一个输出文件\n");
            return 1;
        }

        // 通配符处理: rlezip * output.rzp
        if (argc == 4 && strcmp(argv[2], "*") == 0) {
            compress_current_directory(argv[3]);
        }
        // 多文件压缩模式 (3个或更多参数)
        else if (argc > 4) {
            compress_multiple_files(argc - 3, &argv[2], argv[argc - 1]);
        }
        // 单文件或目录压缩模式
        else {
            DWORD attr = GetFileAttributesA(argv[2]);
            if (attr == INVALID_FILE_ATTRIBUTES) {
                printf("错误: 输入路径不存在 %s\n", argv[2]);
                return 1;
            }

            if (attr & FILE_ATTRIBUTE_DIRECTORY) {
                compress_directory(argv[2], argv[3]);
            }
            else {
                compress_file(argv[2], argv[3]);
            }
        }
    }
    // 处理解压缩命令
    else if (strcmp(argv[1], "unzip") == 0) {
        if (argc < 3) {
            printf("错误: 解压缩命令需要输入文件\n");
            return 1;
        }
        decompress_file(argv[2]);
    }
    // 测试命令
    else if (strcmp(argv[1], "test") == 0) {
        run_rle_tests();
    }
    // 无效命令
    else {
        printf("错误: 无效命令 '%s'\n", argv[1]);
        print_usage(argv[0]);
        return 1;
    }

    return 0;
}

void print_usage(const char* program_name) {
    printf("文件压缩/解压缩工具 (版本 %d)\n", RZP_VERSION);
    printf("用法:\n");
    printf("  压缩单个文件: %s zip <输入文件> <输出文件>\n", program_name);
    printf("  压缩整个目录: %s zip <输入目录> <输出文件>\n", program_name);
    printf("  压缩多个文件: %s zip <文件1> <文件2> ... <输出文件>\n", program_name);
    printf("  压缩当前目录: %s zip * <输出文件>\n", program_name);
    printf("  解压缩      : %s unzip <输入文件>\n", program_name);
    printf("  测试算法    : %s test\n", program_name);
    printf("示例:\n");
    printf("  %s zip myfile.dat compressed.rzp\n", program_name);
    printf("  %s zip mydir backup.rzp\n", program_name);
    printf("  %s zip file1.dat file2.dat file3.dat multi.rzp\n", program_name);
    printf("  %s zip * allfiles.rzp\n", program_name);
    printf("  %s unzip backup.rzp\n", program_name);
}

// ======================
// RLE测试函数（示例）
// ======================

void run_rle_tests() {
    printf("===== RLE算法测试套件 =====\n");

    // 简单测试
    uint8_t test_data[] = { 0x41, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43 };
    size_t test_size = sizeof(test_data);

    uint8_t* compressed = NULL;
    size_t comp_size = 0;
    rle_compress(test_data, test_size, &compressed, &comp_size);

    uint8_t decompressed[10];
    rle_decompress(compressed, comp_size, decompressed, test_size);

    printf("测试: %s\n", memcmp(test_data, decompressed, test_size) == 0 ? "通过" : "失败");
    free(compressed);

    printf("===== 测试完成 =====\n");
}
